package com.mike.employment.base;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;

import com.mike.employment.base.exception.BusinessExcep;
import com.mike.employment.utill.JpaUtil;
import com.mike.employment.utill.NumberUtil;

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class BaseServiceImpl<T> implements BaseService<T> {
	
	public abstract BaseDao<T> getRepository();
	public abstract EntityManager getEntity();

	@Override
	public PageResult getPage(PageRequest req) {
		PageResult<T> result = new PageResult<T>();
		Specification<T> specification  = new Specification<T>() {
            
			/**
			 * 
			 */
			private static final long serialVersionUID = 1L;

			@Override
			public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
				List<Predicate> predicates = new ArrayList<Predicate>();
				if (req.getParameter()!=null) {
					req.getParameter().forEach((k,v)->{
						if (!"updateTime".equals(k) && v!=null && !"".equals(v)) {
							    // 精确匹配
								// Predicate p = criteriaBuilder.equal(root.get(k), v );
								// 模糊匹配
							    if(v instanceof String) {
									Predicate p = criteriaBuilder.like(root.get(k), "%" + v + "%");
									predicates.add(p);
							    }else if (NumberUtil.isNumber(v)) {
									Predicate p = criteriaBuilder.equal(root.get(k), v);
									predicates.add(p);
							    }

						}
					});
				}
				Predicate p = null;
				// 可以通过 condition 参数控制查询条件间的关系
				// 目前使用"and" 查询  可自己扩展
				//if ("and".equals(req.getCondition())) {
					p = criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
				//}else {
				//	p = criteriaBuilder.or(predicates.toArray(new Predicate[predicates.size()]));
				//}
				
				return p;
			}
		};
		 Pageable pageable = org.springframework.data.domain.PageRequest.of(req.getPageNo()-1, req.getPageSize());
		 try{
			 Page<T> page = getRepository().findAll(specification,pageable);
			 result.setTotalPage(page.getTotalPages());
			 result.setTotalCount(page.getTotalElements());
			 result.setPageNo(req.getPageNo());
			 result.setPageSize(req.getPageSize());
			 result.setResult(page.getContent());
			 return result;
		 }catch (Exception e){
		 	log.error("查询异常：",e);
		 	throw new BusinessExcep("分页查询失败!", e);
		 }

	}

	@Transactional
	@Override
	public T add(T t) {
		return getRepository().save(t);
	}

	@Transactional
	@Override
	public void delete(Long id) {
		getRepository().deleteById(id);
	}
	
	@Transactional
	@Override
	public int delete(Long... id) {
		Class<T> tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		String table = tClass.getName().substring(tClass.getName().lastIndexOf(".")+1);
		StringBuffer sb = new StringBuffer("(");
		for (Long l : id) {
			sb.append(l).append(",");
		}
		String ids = sb.toString().substring(0,sb.toString().lastIndexOf(",")) +")";
		String sql = "delete from "+table+" where id in "+ids;
		Query q = getEntity().createQuery(sql);
		int num = q.executeUpdate();
		return num;
	}

	@Transactional
	@Override
	public T update(T t) {
		Class<T> tClass = (Class<T>)((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		String table = tClass.getName().substring(tClass.getName().lastIndexOf(".")+1);
		Method method;
		Long id = 0L;
		try {
			method = t.getClass().getMethod("getId", new Class[] {});
			id = (Long) method.invoke(t, new Object[]{});
		} catch (Exception e) {
			log.error("Update entity error!",e);
		} 
		String sql = "select u from "+table+" as u where u.id="+id;
		EntityManager em = getEntity();
	    List<T> list = em.createQuery(sql, tClass).getResultList();
	    if (list.size()>0) {
	    	T obj = list.get(0);
	    	JpaUtil.copyNullProperties(t, obj);
	    	return getRepository().saveAndFlush(obj);
	    }else {
	    	return null;
	    }
		
	}
	

	@Override
	public T saveOrUpdate(T t){
		try {
			Class clazz = t.getClass().getSuperclass();
			Method getId = clazz.getDeclaredMethod("getId");
			if (null == getId.invoke(t)) {
				return add(t);
			} else {
				return update(t);
			}
		} catch(Exception e) {
			log.error("saveOrUpdate entity error!",e);
			throw new BusinessExcep("saveOrUpdate entity error!", e);
		}
	}

	@Override
	public T findById(Long id) {
		return getRepository().findById(id).orElse(null);
	}
	
	@Override
	public List<T> find(Long... id) {
		List<T> list= getRepository().findAllById(Stream.of(id).collect(Collectors.toList()));
		return list;
	}
	
	@Override
	public List<T> findAll() {
		List<T> list= getRepository().findAll();
		return list;
	}

}
